package zdream.rockchronicle.core.graphics;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;

import java.util.Objects;

import zdream.control.graphics.IPainter;
import zdream.control.world.LevelWorld;
import zdream.control.world.Ticker;
import zdream.rockchronicle.RockChronicle;

import static zdream.control.world.LevelWorld.*;

/**
 * <p>一般的游戏前戏, 也就是在 Level 地图已经准备好, 但是屏幕上主角没出来,
 * 此时屏幕上写着大大的 "READY" 字样;
 * 它也额外处理主角全部离开地图 (可能已经被打败) 之后的退场部分
 * </p>
 *
 * @author Zdream
 * @since 0.0.1
 * @date 2021-09-12 (created)
 * @date 2024-01-04 (last modified)
 */
public class ForeplayPainter implements IPainter {
	public final RockChronicle app;
	public final LevelWorld world;
	public final SpriteBatch batch;

	public ForeplayPainter(RockChronicle app) {
		this.app = Objects.requireNonNull(app);
		this.world = app.levels;
		this.batch = app.graphics.uiBatch;
	}

	/* **********
	 *   绘图   *
	 ********** */

	/**
	 * 包括游戏开始后 / 结束前的黑色渐变;
	 * 包括游戏开始后的 READY 字样;
	 */
//	public final LevelForeplay foreplay;
	private ShapeRenderer renderer;
	public static final long BLACK_CURTAIN_DURATION = 250;
	public static final String READY = "READY";

	{
		renderer = new ShapeRenderer();
	}

	@Override
	public void draw(Ticker ticker) {
		switch (world.state) {
		case STATE_NONE: case STATE_PLAYING:
			break;
		case STATE_READY:
			drawWhenWorldIsReady(ticker);
			break;
		case STATE_OVER:
			drawWhenWorldIsOver(ticker);
			break;
		}
	}

	private void drawWhenWorldIsReady(Ticker ticker) {
		long startTime = world.lastUpdateTime;
		long now = ticker.worldTime;
		long delta = now - startTime;

		// black curtain
		if (delta < BLACK_CURTAIN_DURATION) {
			drawBlackCurtain(batch, 1 - (float) delta / BLACK_CURTAIN_DURATION);
		}

		// ready
		if (delta % 200 > 80) {
			drawReadyText(batch);
		}
	}

	private void drawWhenWorldIsOver(Ticker ticker) {
		long startTime = world.lastUpdateTime;
		long now = ticker.worldTime;

		// black curtain
		long curtainStartTime = startTime + world.endForeplayMillis - BLACK_CURTAIN_DURATION;
		if (now > curtainStartTime) {
			drawBlackCurtain(batch, (now - curtainStartTime) / (float) BLACK_CURTAIN_DURATION);
		}
	}

	private void drawBlackCurtain(SpriteBatch batch, float blackOpacity) {
		Gdx.gl.glEnable(GL20.GL_BLEND); // open alpha channel

		renderer.setProjectionMatrix(batch.getProjectionMatrix());
		renderer.begin(ShapeRenderer.ShapeType.Filled);
		renderer.setColor(0, 0, 0, blackOpacity);
		renderer.rect(-100, -100, app.width + 200, app.height + 200);
		renderer.end();
	}

	private void drawReadyText(SpriteBatch batch) {
		batch.begin();
		BitmapFont font = app.graphics.fontPressStart24;
		font.setColor(Color.WHITE);
		font.draw(batch, READY, app.width / 2f - 60, app.height / 2f + 12);
		batch.end();
	}

	@Override
	public int zIndex() {
		return 15;
	}

	@Override
	public void dispose() {}
}
